import json
import random
from flask import current_app
from Day09.models import User
from Day09.models import Relation

class UserProfileCache(object):
    """
    用户基本信息缓存工具
    """
    def __init__(self, user_id):
        self.user_id = user_id
        self.key = 'user:{}:profile'.format(user_id)
        self.redis_cli = current_app.redis_cluster

    def save(self):
        """
        从数据库中获取用户基本信息,并把数据缓存到redis集群中
        :return:
        """
        user = User.query.get(self.user_id)
        if user:
            # 组装需要缓存的数据
            user_data = {
                'user_id': user.id,
                'mobile': user.mobile,
                'user_name': user.name,
                'photo': user.profile_photo
            }
            # 把用户基本数,缓存到redis集群中
            # 为了演示缓存雪崩,把有效期设置为10秒
            self.redis_cli.setex(self.key, 10, json.dumps(user_data))
            self.redis_cli.setex(self.key, 5*60, json.dumps(user_data))
            # 为了解决缓存雪崩,加上一个随机的整数
            self.redis_cli.setex(self.key, 10 + random.randint(1, 30), json.dumps(user_data))
        else:
            # 组装需要缓存的数据
            user_data = {
                'user_id': -1,
                'mobie': '',
                'user_name':'用户不存在',
                'photo': ''
            }
            # 就算数据库没有数据,在缓存中缓存一条错误数据记录
            self.redis_cli.setex(self.key, 5*60, json.dumps(user_data))
        return user_data
    def get(self):
        """
        对外调用获取用户基本信息的方法
        :return: 用户基本信息
        """
        user_data = self.redis_cli.get(self.key)
        if user_data:
            # 从redis获取的数据都是bytes类型
            return json.loads(user_data.decode())
        else:
            user_data = self.save()
            return user_data

class UserFollowingCache(object):
    """
    获取用户关注列表的缓存层工具
    """
    def __init__(self, user_id):
        self.user_id = user_id
        self.key = 'user:{}:followings'.format(user_id)
        self.redis_cli = current_app.redis_cluster

    def save(self):
        """
        从数据中获取用户关注列表信息，保存到redis集群中。
        :return:
        """
        relations = Relation.query.filter(Relation.user_id == self.user_id, Relation.relation ==
                                          Relation.RELATION.FOLLOW.order_by(Relation.utime.desc()).all())
        # followings是需要返回的关注列表
        followings = []
        # zadd, 使用zadd命令把数据添加到redis中
        # 使用redis事物,pl是一个事务对象
        pl = self.redis_cli.pipeline()
        for i in relations:
            followings.append(i.target_user_id)
            # zadd(self.key, score, member)
            pl.zadd(self.key, i.utime.timestamp(), i.target_user_id)

        # 执行事务
        pl.execute()
        return followings
def get(self):
    """
    获取用户的关注列表，先从缓存中获取，没有再从数据库获取
    :param self:
    :return:
    """
    ret = self.redis_cli.zrevrange(self.key, 0, -1)
    followings = []
    if ret:
        # 遍历从redis中获取到的target_user_id,并转换成整形
        for uid in ret:
            followings.append(int(uid))
        return followings
    else:
        followings = self.save()
        return followings